// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: lucasyoo

#include "coin2/strategy/hamm/util.h"

namespace coin2::strategy::hamm {

constexpr double EPSILON = 1e-8;

bool IsClose(double a, double b) {
  return std::abs(a - b) < EPSILON * (std::abs(a) + std::abs(b));
}

bool IsZero(double a) {
  return std::abs(a) < EPSILON;
}

double LinearTimeDecay(double time_length, double x1, double y1, double y2) {
  return ((time_length - x1) * y1 + x1 * y2) / time_length;
}

int64_t DatetimeToUnixTimestamp(const int64_t& datetime) {
  if (datetime == 1) {
    return 1;
  }
  // datetime: 20220521120000 (YYYYMMDDHHMMSS) in UTC
  auto str_datetime = std::to_string(datetime);
  int year = std::stoi(str_datetime.substr(0, 4));
  int month = std::stoi(str_datetime.substr(4, 2));
  int day = std::stoi(str_datetime.substr(6, 2));
  int hour = std::stoi(str_datetime.substr(8, 2));
  int minute = std::stoi(str_datetime.substr(10, 2));
  int sec = std::stoi(str_datetime.substr(12, 2));
  // get current timeinfo and modify it to the user's choice
  time_t rawtime;
  struct tm timeinfo;
  time(&rawtime);
  auto dt = gmtime_r(&rawtime, &timeinfo);
  dt->tm_year = year - 1900;
  dt->tm_mon = month - 1;    // months since January - [0,11]
  dt->tm_mday = day;          // day of the month - [1,31]
  dt->tm_hour = hour;         // hours since midnight - [0,23]
  dt->tm_min = minute;       // minutes after the hour - [0,59]
  dt->tm_sec = sec;          // seconds after the minute - [0,59]
  
  auto date = mktime(dt);
  
  return static_cast<int64_t>(date) * 1'000'000'000LL;
}

/*
VolatilityCalculator::VolatilityCalculator(
    int64_t window_sec,
    int64_t tick_intv_sec,
    double init_volatility)
    : window_sec_(1'000'000'000LL * window_sec),
      tick_intv_sec_(1'000'000'000LL * tick_intv_sec),
      window_size_(window_sec_ / tick_intv_sec_),
      volatility_(init_volatility) {}

void VolatilityCalculator::UpdatePrice(double midp, int64_t ts) {
  if (prev_midp_ == 0) {
    prev_midp_ = midp;
    last_update_ts_ = ts;
    volatility_ *= midp;  // Since volatility used in paper is having price unit.
                          // With config, we're going to use percentage (unit-free) volatility in
                          // initial condition.
    return;
  }
  auto now_ts = ts;
  if (now_ts - last_update_ts_ < tick_intv_sec_) {
    return;
  }

  double diff = midp - prev_midp_;
  if (diffs_.size() < window_size_) {
    diffs_.push_back(diff);
    square_sum_ += diff * diff;
  } else {
    double& prev_elem = diffs_.front();
    diffs_.pop_front();
    diffs_.push_back(diff);
    square_sum_ += -prev_elem * prev_elem + diff * diff;
  }
  last_update_ts_ = now_ts;
  CalculateVolatility();
}

void VolatilityCalculator::CalculateVolatility() {
  const size_t sz = diffs_.size();
  if (sz < window_size_) {
    return;
  }
  if (square_sum_ > 0.0) volatility_ = std::sqrt(square_sum_ / sz);
}
*/

}  // namespace coin2::strategy::hamm
